package cn.lyf.currey;

import java.util.*;
import static cn.lyf.currey.Tuple.*;
import static cn.lyf.currey.Currying.*;
import java.util.function.*;
// 简单缓存
public class Cache {

    public static <A, B, C, D, E, F> f5<A, B, C, D, E, F> memoize(
            f5<? super A, ? super B, ? super C, ? super D, ? super E, ? extends F> fx) {
        final Map<Tuple5<A, B, C, D, E>, F> cache = new HashMap<>();
        return (a, b, c, d, e) -> {
            F f = cache.get(of(a, b, c, d, e));
            if (f == null) {
                f = fx.apply(a, b, c, d, e);
                cache.put(of(a, b, c, d, e), f);
            }
            return f;
        };
    }

    public static <A, B, C, D, E> f4<A, B, C, D, E> memoize(
            f4<? super A, ? super B, ? super C, ? super D, ? extends E> fx) {
        final Map<Tuple4<A, B, C, D>, E> cache = new HashMap<>();
        return (a, b, c, d) -> {
            E f = cache.get(of(a, b, c, d));
            if (f == null) {
                f = fx.apply(a, b, c, d);
                cache.put(of(a, b, c, d), f);
            }
            return f;
        };
    }

    public static <A, B, C, D> f3<A, B, C, D> memoize(f3<? super A, ? super B, ? super C, ? extends D> fx) {
        final Map<Tuple3<A, B, C>, D> cache = new HashMap<>();
        return (a, b, c) -> {
            D f = cache.get(of(a, b, c));
            if (f == null) {
                f = fx.apply(a, b, c);
                cache.put(of(a, b, c), f);
            }
            return f;
        };
    }

    public static <A, B, C> f2<A, B, C> memoize(BiFunction<? super A, ? super B, ? extends C> fx) {
        final Map<Tuple2<A, B>, C> cache = new HashMap<>();
        return (a, b) -> {
            C f = cache.get(of(a, b));
            if (f == null) {
                f = fx.apply(a, b);
                cache.put(of(a, b), f);
            }
            return f;
        };
    }

    public static <A, B> f1<A, B> memoize(Function<? super A, ? extends B> fx) {
        final Map<A, B> cache = new HashMap<>();
        return a -> {
            B f = cache.get(a);
            if (f == null) {
                f = fx.apply(a);
                cache.put(a, f);
            }
            return f;
        };
    }

}
